package games.eightPuzzle;

import java.util.ArrayList;
import java.util.Collections;

import commonDataStructures.BinaryHeap;
import commonDataStructures.PQueue;
import commonDataStructures.PSingleCollection;
import commonDataStructures.PStack;
import commonDataStructures.PrimitiveQueue;

import games.eightPuzzle.states.SlidingPuzzleState;
import genetics.DescendantCreator;


/**
 * @author alazar2
 * this clas runs the tests
 */
public class Platform {

	private static final int GENETIC_POPULATION = 20;
	private SlidingPuzzleState _sState;
	private SlidingPuzzleState _fState;

	public Platform(String[] args){
		_sState = new SlidingPuzzleState(args[0]);
		_fState = new SlidingPuzzleState(args[1]);
		SolutionBank.setOutputPath(args[2]);
	}

	public void runBFSTest(){
		SlidingPuzzle sp = new SlidingPuzzle(new PrimitiveQueue<SlidingPuzzleState>(),
				_sState,
				_fState);
		SolutionBank.addSolution(sp.runTest(1));
		SolutionBank.loadFinalSolution();
		SolutionBank.printSolution();	
	}

	public void runDFSTest(){
		SlidingPuzzle sp = new SlidingPuzzle(new PStack<SlidingPuzzleState>(),
				_sState,
				_fState);
		SolutionBank.addSolution(sp.runTest(1));
		SolutionBank.loadFinalSolution();
		SolutionBank.printSolution();	
	}

	public void runAStarTest(){
		SlidingPuzzle sp = new SlidingPuzzle(new BinaryHeap<SlidingPuzzleState>(),
				_sState,
				_fState);
		SolutionBank.addSolution(sp.runTest(1));
		SolutionBank.loadFinalSolution();
		SolutionBank.printSolution();	
	}

	public void runGeneticTest(){
		ArrayList<SolutionInfo> solutions = new ArrayList<SolutionInfo>();
		for(int i=0;i<GENETIC_POPULATION;i++){
			System.out.println("TEST #"+i);
			SlidingPuzzle sp = new SlidingPuzzle(new BinaryHeap<SlidingPuzzleState>(),
					_sState,
					_fState);
			SolutionInfo sol = sp.runTest(5);
			if (sol.hasSolution()){
				solutions.add(sol);	
			}
		}
		int totalNodes=0;
		int totalTime=0;
		for(SolutionInfo s:solutions){
			try{
				totalNodes+=s.getNodesExpantionNumber();
				totalTime+=s.getTime();
				System.out.println("Length: "+s.getSolutionLength());
				System.out.println("Nodes: "+s.getNodesExpantionNumber());
				System.out.println("Time: "+s.getTime());
				System.out.println("##################");
			}catch(Exception e){
				System.out.println("No solution");
			}
		}

		System.out.println("Genetic process has started");

		int populationSize = GENETIC_POPULATION*GENETIC_POPULATION;

		ArrayList<SolutionInfo> tmpArr = new ArrayList<SolutionInfo>();

		DescendantCreator<SlidingPuzzleState> d = new DescendantCreator<SlidingPuzzleState>();

		
		while (populationSize>1){
			tmpArr.clear();
			for(int i=0;i<solutions.size();i++){
				for(int j=i+1;j<solutions.size();j++){
					ArrayList<SlidingPuzzleState> son = d.generateDescendant(
							solutions.get(i).getSolutionTrace(),
							solutions.get(j).getSolutionTrace());
					tmpArr.add(new SolutionInfo(son,0,0,false));
				}
			}
			populationSize/=2;
			Collections.sort(tmpArr);
			solutions.clear();
			for(int i=0;i<tmpArr.size() && i<populationSize;i++){
				solutions.add(tmpArr.get(i));
			}
		}
		
		if (solutions.isEmpty()){
			System.out.println("GENETIC: no final solution has been dound, probably error");
		}else{
			for(SolutionInfo s:solutions){
				try{
					System.out.println("Length: "+s.getSolutionLength());
					System.out.println("Nodes: "+s.getNodesExpantionNumber());
					System.out.println("Time: "+s.getTime());
					System.out.println("##################");
				}catch(Exception e){
					System.out.println("No solution");
				}
				System.out.println("TotalNodes: "+totalNodes);
				System.out.println("TotalTime: "+totalTime);
			}	
		}

	}

	public void runHillClimbingTest(){
		SlidingPuzzle sp = new SlidingPuzzle(new PSingleCollection<SlidingPuzzleState>(),
				_sState,
				_fState);
		SolutionBank.addSolution(sp.runTest(1));
		SolutionBank.loadFinalSolution();
		SolutionBank.printSolution();	
	}

	

	public static void main(String[] args){
		//new Platform(args).runGeneticTest();
		new Platform(args).runHillClimbingTest();
	}
}
